/* 
 * File:   main.cpp
 * Author: Chen Liu
 * Student number: 3996591
 *
 * Created on October 18, 2012, 2:16 AM
 */

/*
 * Task 3
 * Base on the principle of these algorithms, the SSTF is the only one may 
 * cause starvation. The reason of starvation is a certain request is far away
 * from others, which means its seek distance is larger than other's, and always
 * at the end of the sequence. A method may solve this problem is add a counter.
 * When a request arrival, it will be assign a counter. After finishing one 
 * request, release its counter, and add one to all other counters. Then set up
 * a boundary value with a certain number. if one counter arrival this value, 
 * then the process will response  this request as the next. The key problem is 
 * the setting of boundary value. If the value is too small, the performance will
 * reduce rapidly, if the value is too large, there is still chance to have 
 * starvation. So the value must be setup carefully.
 * 
 * In my opinion, the mechanisms to switch from different algorithms is as 
 * following:
 * 1. Normally, use the SSTF or LOOK (C-LOOK) algorithm, depend on the size of
 *    the disk per head 
 * 2. After a certain time (set by the OS), turn into the FCFS, response the 
 *    first 100(or any number set by the OS) requests, and then turn back to 
 *    SSTF or LOOK (C-LOOK) algorithm
 * 3. If the size of the sequence reach a certain number (e.g. 100000), then 
 *    switch into SCAN or C-SCAN algorithm, which is suitable for a heavy load 
 *    on disk. During the SCAN or C-SCAN algorithm, if the size of the sequence 
 *    reduce to a certain number(e.g. 500), switch back to SSTF or LOOK (C-LOOK)
 *    algorithm.
 */

#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include "disk.h"
#include <vector>

using namespace std;

int main(int argc, char* argv[]) {

    int seed;
    int numt; //number of track
    int hspeed; //head speed
    int numtr; //number of track request
    int minreq; //min request
    int maxreq; //max request
    int inc; //increment
    int *refs; //reference string

    /*
    seed = 1234;
    numt = 10000;
    hspeed = 100;
    numtr = 5000;
    minreq = 100;
    maxreq = 500;
    inc = 50;
    */

    cout << "Enter rand seed: ";
    cin >> seed;

    cout << "Enter no. of tracks on disk: ";
    cin >> numt;

    cout << "Enter head speed (tracks/ms): ";
    cin >> hspeed;

    cout << "Enter no. of track requests: ";
    cin >> numtr;

    cout << "Enter min no. of track requests per second: ";
    cin >> minreq;

    cout << "Enter max no. of track requests per second: ";
    cin >> maxreq;
    if (!(maxreq > minreq)) {
        cout << "The max no. of track should be larger than min." << endl;
        return 0;
    }

    cout << "Enter track request increment: ";
    cin >> inc;

    srand(seed);

    refs = new int[numtr];
    for (int i = 0; i < numtr; i++) {
        refs[i] = rand() % numt;
    }

    vector<int> column;
    
    DiskScheduler diskScheduler(numt, hspeed, refs, numtr);
    cout << endl;
    cout << setw(40) << "TOTAL SEEK TiME (Secs) " << endl;
    cout << setw(10) << setiosflags(ios::left) << "Reqs:";
    for (int i = minreq; i <= maxreq; i = i + inc) {
        cout << setw(10) << i;
        column.push_back(i);
    }
    
    cout << endl;
    cout << setw(10) << "FCFS:";
    for (int i=0; i<column.size();i++) {
        cout << setw(10) << setiosflags(ios::fixed) << setprecision(3)
                << diskScheduler.AccessDisk(eFCFS, column[i]) / 1000;
    }

    cout << endl;
    cout << setw(10) << "SSTF:";
    for (int i=0; i<column.size();i++) {
        cout << setw(10) << setiosflags(ios::fixed) << setprecision(3)
                << diskScheduler.AccessDisk(eSSTF, column[i]) / 1000;
    }
    cout << endl;

    cout << setw(10) << "SCAN:";
    for (int i=0; i<column.size();i++) {
        cout << setw(10) << setiosflags(ios::fixed) << setprecision(3)
                << diskScheduler.AccessDisk(eSCAN, column[i]) / 1000;
    }
    cout << endl;

    cout << setw(10) << "CSCAN:";
    for (int i=0; i<column.size();i++) {
        cout << setw(10) << setiosflags(ios::fixed) << setprecision(3)
                << diskScheduler.AccessDisk(eCSCAN, column[i]) / 1000;
    }
    cout << endl;

    cout << setw(10) << "LOOK:";
    for (int i=0; i<column.size();i++) {
        cout << setw(10) << setiosflags(ios::fixed) << setprecision(3)
                << diskScheduler.AccessDisk(eLOOK, column[i]) / 1000;
    }
    cout << endl;

    cout << setw(10) << "CLOOK:";
    for (int i=0; i<column.size();i++) {
        cout << setw(10) << setiosflags(ios::fixed) << setprecision(3)
                << diskScheduler.AccessDisk(eCLOOK, column[i]) / 1000;
    }
    cout << endl;

    return 0;
}

